using System;
using System.Collections.Generic;

namespace ZyGame.Subscribes
{
    public abstract class GameEventArgs<T> : IDisposable where T : GameEventArgs<T>
    {
        private Queue<object> paramsList = new Queue<object>();

        public virtual void Dispose()
        {
            paramsList.Clear();
        }

        public TR GetEventData<TR>()
        {
            if (paramsList.Count is 0)
            {
                return default;
            }

            return (TR)paramsList.Dequeue();
        }

        public static void Subscribe(Action<T> callback)
        {
            Subscribe(DefaultSubscribe.Create(callback));
        }

        public static void Subscribe(ISubscribe callback)
        {
            SubjectManager.instance.Add<T>(callback);
        }

        public static void Unsubscribe(Action<T> callback)
        {
            SubjectManager.instance.Remove(DefaultSubscribe.GetSubscribe(callback));
            DefaultSubscribe.Remove(callback);
        }

        public static void Unsubscribe(ISubscribe callback)
        {
            SubjectManager.instance.Remove(callback);
        }

        public static void Clear()
        {
            SubjectManager.instance.Clear<T>();
        }

        public static void ExecuteSubscribe(T args)
        {
            SubjectManager.instance.Execute(args);
        }

        public static void ExecuteSubscribe(params object[] dataList)
        {
            T args = Activator.CreateInstance<T>();
            foreach (var VARIABLE in dataList)
            {
                args.paramsList.Enqueue(VARIABLE);
            }

            SubjectManager.instance.Execute(args);
        }

        class DefaultSubscribe : ISubscribe
        {
            private Action<T> callback;
            private static List<DefaultSubscribe> _list = new List<DefaultSubscribe>();

            public static DefaultSubscribe Create(Action<T> callback)
            {
                DefaultSubscribe subscribe = GetSubscribe(callback);
                if (subscribe is not null)
                {
                    Client.Console.WriteLine("The Event Subscribe is already exits");
                }

                subscribe = new DefaultSubscribe();
                subscribe.callback = callback;
                return subscribe;
            }

            public static DefaultSubscribe GetSubscribe(Action<T> callback)
            {
                return _list.Find(x => x.callback == callback);
            }

            public static void Remove(Action<T> callback)
            {
                DefaultSubscribe subscribe = GetSubscribe(callback);
                if (subscribe is null)
                {
                    return;
                }

                _list.Remove(subscribe);
            }

            public void Execute(object args)
            {
                try
                {
                    this.callback?.Invoke((T)args);
                }
                catch (Exception e)
                {
                    Client.Console.WriteLine(e);
                    throw;
                }
            }

            public void Dispose()
            {
                callback = null;
            }
        }
    }
}